/**
 * Copyright 2011 Honeywell Federal Manufacturing & Technologies, LLC. This material was produced under U.S. Government
 * contract DE-ACO4-01AL66850, Honeywell Federal Manufacturing & Technologies, LLC, (FM&T) with the U. S. Department of
 * Energy for the operation of the Kansas City Plant . The U.S. Government has rights to use, reproduce, and distribute
 * this software.  NEITHER THE GOVERNMENT NOR Honeywell Federal Manufacturing & Technologies, LLC, MAKES ANY WARRANTY,
 * EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE.  If software is modified to produce
 * derivative works, such modified software should be clearly marked, so as not to confuse it with the version available
 * from FM&T.
 *
 * Additionally, this program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License Version 3 published by the Free Software Foundation. Accordingly, this program is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this library.
 * If not, see http://www.gnu.org/licenses/.
 */
package org.braintrain.tapestry.view;

import com.javaforge.tapestry.spring.annotations.InjectSpring;
import com.kcp.ko.fmtnmlib.tapestry.form.EnumPropertySelectionModel;
import org.apache.tapestry.IAsset;
import org.apache.tapestry.IExternalPage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.annotations.*;
import org.apache.tapestry.form.IFormComponent;
import org.apache.tapestry.form.IPropertySelectionModel;
import org.apache.tapestry.valid.ValidationDelegate;
import org.braintrain.domain.Content;
import org.braintrain.domain.Module;
import org.braintrain.domain.Navigation;
import org.braintrain.domain.TestData;
import org.braintrain.domain.types.ModuleNumbering;
import org.braintrain.domain.types.NavigationType;
import org.braintrain.services.NavigationService;
import org.braintrain.services.search.DuplicationCheckCriteria;
import org.braintrain.tapestry.aso.TestASO;

import java.util.List;

/**
 * Tapestry ModuleAdmin page.  This page gives the ContentCreator and CM-Staff users the ability
 * to modify the content on the module scale.  Features:
 * 1.  Rename and change the description of a module
 * 2.  Release content, save, or retire a module
 * 3.  Change the order of the content
 * 4.  Manage all pages associated with module
 * 5.  Determine what has changed since the previous release of a module
 * 
 * @author John Ericksen
 *
 */
public abstract class ModuleAdmin extends BrainTrainSecuredBasePage implements IExternalPage{
    
    public static final String ExternalName = "ModuleAdmin";

    //Image Assets
    @Asset("/images/undo.gif")
    public abstract IAsset getBackImage();    
    
    @Asset("/images/add.gif")
    public abstract IAsset getAddImage();  
    
    @Asset("/images/close.gif")
    public abstract IAsset getOffImage();
    
    @Asset("/images/checked.gif")
    public abstract IAsset getOnImage();
    
    @Asset("/images/thumbcontent.gif")
    public abstract IAsset getContentThumbImage();
    @Asset("/images/thumbtest.gif")
    public abstract IAsset getTestThumbImage();
    @Asset("/images/thumbdeletedcontent.gif")
    public abstract IAsset getDeletedContentThumbImage();
    @Asset("/images/thumbdeletedtest.gif")
    public abstract IAsset getDeletedTestThumbImage();
    @Asset("/images/thumbeditedcontent.gif")
    public abstract IAsset getEditedContentThumbImage();
    @Asset("/images/thumbeditedtest.gif")
    public abstract IAsset getEditedTestThumbImage();
    
    @InjectSpring("navigationService")
    public abstract NavigationService getNavigationService();
    
    @Bean
    public abstract ValidationDelegate getDefaultDelegate();
    
    //Page Injections
    @InjectPage("View")
    public abstract View getViewPage();
    
    @InjectPage("Test")
    public abstract Test getTestPage();
    
    @InjectPage("EditTest")
    public abstract EditTest getEditTestPage();
    
    @InjectPage("Home")
    public abstract Home getHomePage();
    
    @InjectPage("ViewAll")
    public abstract ViewAll getViewAllPage();
    
    public abstract void setNavigation(Navigation page);
    public abstract Navigation getNavigation();
    
    public abstract List<Navigation> getNavigationChain();
    public abstract void setNavigationChain(List<Navigation> l);
    
    @InjectState("testaso")
    public abstract TestASO getTestASO();    
    
    @Persist
    @InitialValue("new org.braintrain.domain.Module()")
    public abstract Module getNewModule();
    public abstract void setNewModule(Module m);

    @Persist("client")
    public abstract Long getEditableKey();
    public abstract void setEditableKey(Long key);

    /**
     * Current Module
     * @return
     */
    public Module getModule(){
        return getEditingASO().getEditable(Module.class, getEditableKey(), getRequestCycle().isRewinding(), getNewModule());
    }
    
   public void activateExternalPage(Object[] parameters, IRequestCycle cycle) {
       if(parameters != null && parameters.length > 0 && parameters[0] instanceof Long)
       {
           activate(cycle, (Long)parameters[0]);
       }
       else
       {
           cycle.activate(getHomePage());
       }
   }

    /**
     * Initialize the current page with a given module (or new module)
     */
    public void activate(IRequestCycle cycle)
    {
        setEditableKey(getEditingASO().checkinEditable(getNewModule()));

        cycle.activate(this);
    }
   
    
    /**
     * Initialize the current page with a given module (or new module)
     */
    public void activate(IRequestCycle cycle, Long moduleId)
    {
        Module module = getGenericService().getById(Module.class, moduleId);
        setEditableKey(getEditingASO().checkinEditable(module));
        
        cycle.activate(this);
    }
    
    
    /**
     * Release Module Listener
     */
    public void releaseModule(IRequestCycle cycle)
    {
        if(getModule().isActive() || validate()){
            getNavigationService().saveRelease(getModule());
        }
        //todo:redirect
    }
    
    /**
     * Retire Module Listener
     */
    public void retireModule(IRequestCycle cycle)
    {
        if(validate()){
            getModule().setRetired(!getModule().isRetired());
            getModule().setActive(false);
            
            getGenericService().saveOrUpdate(getModule());
        }
        //todo:redirect
    }
    
    /**
     * link to the first page (creates one if getfirst == null)
     */
    public void firstPageLink(IRequestCycle cycle)
    {
        
        List<Navigation> mainChain = getNavigationService().getMainDeltaNavigationChain(getModule(), false);
        
        Navigation first = null;
        if(mainChain.size() > 0)
        {
            first = mainChain.get(0);
        }
        
        if(first != null)
        {
            
        
            if(first.isTest())
            {
                getTestPage().activate(cycle, first.getId(), null);
            }
            else
            {
                View view = getViewPage();
                view.activate(cycle, first.getId(), null);
            }
        }
    }
    
    /**
     * Add a page (main chain)
     */
    public void addContentLink(IRequestCycle cycle)
    {
        Navigation navigation = new Navigation();
        navigation.getNullSafeContent().setDeltaValue(new Content());
        navigation.setMainNavigation(true);
        navigation.setType(NavigationType.View);
           
        getModule().getMainPages().add(navigation);
        navigation.setModule(getModule());

        getGenericService().saveOrUpdate(navigation);
        
        View view = getViewPage();
        view.setEditContent(true);
        view.activate(cycle, navigation.getId(), null);
    }
    
    /**
     * Add a test (main chain)
     */
    public void addTestLink(IRequestCycle cycle)
    {
        Navigation navigation = new Navigation();
        navigation.getNullSafeContent().setDeltaValue(new TestData());
        navigation.setMainNavigation(true);
        navigation.setType(NavigationType.Test);
           
        getModule().getMainPages().add(navigation);
        navigation.setModule(getModule());
        
        getGenericService().saveOrUpdate(navigation);
            
       
        getEditTestPage().activate(cycle, navigation.getId(), null);
        
    }
    
    /**
     * Validate the module's changes
     * @return
     */
    public boolean validate()
    {
    	if(getModule().getNullSafeName().getDeltaValue() == null || getModule().getNullSafeName().getDeltaValue().length() == 0)
        {
            getDefaultDelegate().record((IFormComponent)getComponent("moduleNameEdit"), "Module must have a name to be saved.");
        }
        else
        {
            List<Module> testModule = (List<Module>)getGenericService().find(new DuplicationCheckCriteria(Module.class, "name.value", getModule().getNullSafeName().getDeltaValue(), getModule().getId()));
            if(testModule != null && testModule.size() > 0)
            {
                getDefaultDelegate().record((IFormComponent)getComponent("moduleNameEdit"), "Module Name already exists, please rename.");
            }
        }
        if(getModule().getNullSafeDescription().getDeltaValue() != null && getModule().getNullSafeDescription().getDeltaValue().length() > 4000)
        {
            getDefaultDelegate().record((IFormComponent)getComponent("moduleDescriptionEdit"), "Module Description must be less than 4000 characters long.");
        }
        return !getDefaultDelegate().getHasErrors();
    }
    
    /**
     * Save pending changes to the module
     */
    public void saveSubmit(IRequestCycle cycle)
    {
        if(validate())
        {
            Module saveMe = getModule();
            getGenericService().saveOrUpdate(saveMe);
            this.activate(cycle, saveMe.getId());
        }
        //todo:redirect
    }
    
    /**
     * Cancel and pending changes
     */
    public void cancelSubmit(IRequestCycle cycle)
    {
        cycle.activate(getHomePage());
        //todo:redirect
    }

    
    /**
     * Retuns a list of navigations... the main chain
     * @return
     */
    public List<Navigation> getInOrderMainPages()
    {
       return getNavigationService().getMainDeltaNavigationChain(getModule(), true);
        
    }
    
    /**
     * Returns a list or list of navigations.. the lined chains
     * @return
     */
    public List<List<Navigation>> getLinkedPages()
    {
       return getNavigationService().getLinkedChains(getModule(), true, true);
    }
    
   
    
    /**
     * Goes to the ViewAll Page to view the entire produciton listing of modules content
     * @param cycle
     */
    public void allContent(IRequestCycle cycle)
    {
        getViewAllPage().activate(cycle, getModule(), false);
    }
    
    /**
     * Goes to the ViewAllDelta Page to view the entire delta listing of modules content
     * @param cycle
     */
    public void allDeltaContent(IRequestCycle cycle)
    {
        getViewAllPage().activate(cycle, getModule(), true);
    }
    
    /**
     * Call into the NavigationService to remove all pending changes
     * commented out because this is too distructive
     * @param cycle
     */
    /*public void syncDeltaWithReleased(IRequestCycle cycle)
    {
       getNavigationService().saveSyncDeltaWithReleased(getModule());
    }*/
    
    /**
     * Inactivate the Module.  Set Active to false.
     */
    public void inactivateModule(IRequestCycle cycle)
    {
        if(validate())
        {
            getModule().setActive(false);
            
            getGenericService().saveOrUpdate(getModule());
        }
    }
    
    /**
     * Property Selection models
     */
    private static IPropertySelectionModel pageNumberingPSModel = new EnumPropertySelectionModel<ModuleNumbering>(ModuleNumbering.values(), "name");

    public static IPropertySelectionModel getPageNumberingPSModel() {
        return pageNumberingPSModel;
    }

    
}
